#include"Task.hpp"
#include <iostream>
#include <unistd.h>
#include <cassert>
#include <string>
#include <vector>
#include<time.h>
#include<sys/wait.h>
#include<sys/types.h>
#include<sys/stat.h>
const int processnum = 5;
std::vector<task_t> tasks;
// 先描述
class channel
{
public:
    channel(int cmdfd, pid_t slaverid, std::string slavername)
        : _cmdfd(cmdfd), _slaverid(slaverid), _slavername(slavername)
    {
    }

public:
    int _cmdfd;              // 读写端的fd
    pid_t _slaverid;         // 子进程的id
    std::string _slavername; // 子进程名字
};

//子进程的工作
void Slaver()
{
    //int cnt=0;
    while(true)
    {
        // std::cout<<"i am running "<<getpid()<<std::endl;
        // sleep(1);
        // cnt++;
        // if(cnt>5) break;
        int code=0; //任务码
        int n=read(0,&code,sizeof(int)); //固定每次读取4字节
        if(n==sizeof(int))
        {
            //对应执行code的任务列表
            std::cout<<"Slaver say@ get a command: "<<getpid()<<"code: "<<code<<std::endl;
            if(code>=0 &&code<tasks.size()) tasks[code]();
            
        }
        if(n==0) break;
    }
}

// 输出型参数用*
// 输入型const&
// 输入输出型&
void InitProcessPool(std::vector<channel> *channels)
{
    std::vector<int> oldfd;
    for (int i = 0; i < processnum; i++)
    {
        // 创建管道
        int pipefd[2] = {0};
        int n = pipe(pipefd);
        // 检查管道是否创建成功
        assert(!n);
        (void)n;

        // 创建父子进程
        pid_t id = fork();
        if (id < 0)
        {
            perror("fork");
            return ;
        }
        else if (id == 0) // child
        {
            for(auto fd:oldfd)
            {
                std::cout<<"close history fd";
                close(fd);
            }
            std::cout<<std::endl;

            // 关闭写端
            close(pipefd[1]);
            //子进程要完成的任务，重定向，向标准输入读
            dup2(pipefd[0],0);
            close(pipefd[0]);
            Slaver();
            std::cout << "process : " << getpid() << " quit" << std::endl;
            exit(0);
        }
        // father
        // 关闭读端
        close(pipefd[0]);
        //增加channel字段了
        std::string name="process-"+std::to_string(i);
        channels->push_back(channel(pipefd[1],id,name));
        oldfd.push_back(pipefd[1]);
        sleep(1);
    }
}

void Menu();

void CtrlSlaver(const std::vector<channel>&channels)
{
   int which=0;
    while (true)
    {
         int seclet=0;
         Menu();
         std::cout<<"Please Enter@ ";
         std::cin>>seclet;
         if(seclet<=0 ||seclet>=5) break;
        // 选择任务
        // int code = rand() % tasks.size();
        int code=seclet-1;
        // 选择进程
        //int processpos = rand() % channels.size();
        std::cout << "father say: " << "code " << code << "already send to " << channels[which]._slaverid << "processname "
                  << channels[which]._slavername << std::endl;
        // 发送任务
        write(channels[which]._cmdfd, &code, sizeof(code));
        which++;
        which%=channels.size();
        //sleep(1);
    }
}
void Menu()
{
    std::cout<<"##########################################"<<std::endl;
    std::cout<<"###1.这是一个日志任务   2.刷新野怪##########"<<std::endl;
    std::cout<<"###3.恢复蓝条   4.检查是否需要更新##########"<<std::endl;
    std::cout<<"###0.退出           #######################"<<std::endl;
    std::cout<<"###########################################"<<std::endl;
    std::cout<<"###########################################"<<std::endl;
}
void Debug(const std::vector<channel>&channels)
{
    for(auto&c:channels)
    {
        std::cout<<c._slavername<<","<<c._slaverid<<","<<","<<c._cmdfd<<std::endl;
    }
}

void QuitProcess(const std::vector<channel>&channels)
{
    //version2
    for(auto&c:channels)
    {
        close(c._cmdfd);
        waitpid(c._slaverid,nullptr,0);
    }
    // version1
    // int last=channels.size()-1;
    // for(int i=last;i>=0;i--)
    // {
    //     close(channels[i]._cmdfd);
    //     waitpid(channels[i]._slaverid,nullptr,0);
    // }
    //bug!!
    // for (auto &c : channels)
    // {
    //     close(c._cmdfd);
    // }
    // for (auto &c : channels)
    // {
    //     waitpid(c._slaverid, nullptr, 0);
    // }
    sleep(1);
}

int main()
{
    LoadTask(&tasks);
    //随机数种子
    srand(time(nullptr)^1023);
    // 再组织
    std::vector<channel> channels;
    // 初始化--创建多个子进程
    InitProcessPool(&channels);
    //测试
    Debug(channels);
    //开始控制子进程
    CtrlSlaver(channels);
    
    //清理收尾
    QuitProcess(channels);
    // std::cout<<"进程退出"<<std::endl;
    return 0;
}